package com.cqw.robot.core;

import com.cqw.robot.model.PicAct;
import com.cqw.robot.utils.KeyboardUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import nu.pattern.OpenCV;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Random;

@Slf4j
public class MyApplication {

    public final static Random random = new Random();

    static List<PicAct> getBaiduIp(){
        List<PicAct> acts = new ArrayList<PicAct>() {{
            add(new PicAct("/images/baidu-ip/1file.png", 2, 1500));
            add(new PicAct("/images/baidu-ip/2file.png", 0, 1000));
            add(new PicAct("ip",                         4));
            add(new PicAct("/images/baidu-ip/3file.png", 0));
        }};
        return acts;
    }

    public static void init(Robot robot) {
        log.info("DEBUG:。。。myApplication START。。。");
        robot.setAutoDelay(1);
        activeMyWindow(robot, new PicAct(null, 2), new Point(36, 227 ));
    }

    public static void oper(Robot robot) {
        showDesktop(robot);
        log.info("DEBUG:。。。myApplication START。。。");
        operByPath(robot, getBaiduIp());
    }


    @SneakyThrows
    public static void operByPath(Robot robot, List<PicAct> acts){

        Optional.ofNullable(acts).orElse(new ArrayList<>()).forEach(a ->{
            runEvent(robot, a);
            long time = a.getTime();
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }


    static void runEvent(Robot robot, PicAct picAct){

        String path = picAct.getPath();
        Integer act = picAct.getAct();
        Point p = picAct.getPoint();

        robot.setAutoDelay(100);
        if(act < 3){
            String userDir = System.getProperty("user.dir");
//            ImageFindDemo demo = new ImageFindDemo(userDir + path);
//            Point point = demo.printFindData();
            Point point = matchTemplate(userDir + path, 0.3);
            log.info("point:{}",point);
            moveAndClick(robot, point, act);
        }else if(act == 3){/** 输入 */
            input(robot, path);
        }else if(act == 4){/** 输入并回车 */
            input(robot, path);
            robot.keyPress(KeyEvent.VK_ENTER);
            robot.keyRelease(KeyEvent.VK_ENTER);
        }else if(act == 5){/** 坐标双击 */
            moveAndClick(robot, p, 2);
            robot.keyPress(KeyEvent.VK_ENTER);
            robot.keyRelease(KeyEvent.VK_ENTER);
        }
    }



    public static void activeMyWindow(Robot robot, PicAct picAct, Point point){
        Integer act = picAct.getAct();
        showDesktop(robot);
        moveAndClick(robot, point, act);
    }


    @SneakyThrows
    private static void moveAndClick(Robot robot, Point point, int button) {
        if (null != point) {
            moveTo(robot, point);
        }
        if (0 == button) {
            robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
            getRandomSleep();
            robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
        } else if (1 == button) {
            robot.mousePress(InputEvent.BUTTON3_MASK);
            robot.mouseRelease(InputEvent.BUTTON3_MASK);
        } else if (2 == button) {
            robot.mousePress(InputEvent.BUTTON1_MASK);
            robot.mouseRelease(InputEvent.BUTTON1_MASK);
            robot.mousePress(InputEvent.BUTTON1_MASK);
            robot.mouseRelease(InputEvent.BUTTON1_MASK);
        } else if (-1 == button) {

        }
        Thread.sleep(20L);
    }

    public static void moveTo(Robot robot, Point point) {
        try {
            if (1 == 1) {
                robot.mouseMove(point.x, point.y);
                getRandomSleep();
                return;
            }
            PointerInfo curPoint = MouseInfo.getPointerInfo();
            Point currentPoint = curPoint.getLocation();
            int curX = currentPoint.x;
            int curY = currentPoint.y;
            int diffX = point.x - curX;
            int diffY = point.y - curY;
            int positiveX = diffX > 0 ? 1 : -1;
            int positiveY = diffY > 0 ? 1 : -1;
            //步长
            int step = Math.min(Math.abs(diffX), Math.abs(diffY));
            for (int i = 0; i < step; i++) {
                robot.mouseMove(curX, curY);
                curX = curX + 1 * positiveX;
                curY = curY + 1 * positiveY;
            }
            int surplusX = Math.abs(diffX) - step;
            int surplusY = Math.abs(diffY) - step;
            for (int i = 0; i < surplusX; i++) {
                robot.mouseMove(curX, curY);
                curX = curX + 1 * positiveX;
            }
            for (int i = 0; i < surplusY; i++) {
                robot.mouseMove(curX, curY);
                curY = curY + 1 * positiveY;
            }
        } catch (Exception e) {
            log.info("错误:{}",e);
        }
    }

    @SneakyThrows
    public static void getRandomSleep(){
        int sleepTime = random.nextInt(10) + 200;
        Thread.sleep(sleepTime);
    }


    /** 显示桌面 */
    static void showDesktop(Robot robot){
        // 移动鼠标到屏幕的中间
        robot.mouseMove(
                (int) (Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2),
                (int) (Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2)
        );
        // 模拟按下键盘上的“Windows”键或者“Command”键（根据操作系统而异）
        robot.keyPress(KeyEvent.VK_WINDOWS);

        // 等待一段时间以便操作系统响应
        robot.delay(100);

        // 模拟按下“D”键，代表显示桌面
        robot.keyPress(KeyEvent.VK_D);

        // 释放按键
        robot.keyRelease(KeyEvent.VK_WINDOWS);
        robot.keyRelease(KeyEvent.VK_D);
    }


    /**
     * 输入字符串
     *
     * @param s
     * @return
     */
    public static boolean input(Robot r, String s)
    {
        log.info("输入字符串："+ s);
        try {
            KeyboardUtils.write(r, s);
        }catch (Exception e)
        {
            log.error("输入失败："+s);
            return false;
        }
        return true;
    }


    /**
     * 全屏截图
     * @return 返回BufferedImage
     */
    @SneakyThrows
    public static Mat getFullScreenShotByFile() {

        String fileName = File.separator + System.currentTimeMillis() + "file.png";
        int width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();
        int height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();
        Robot robot = new Robot();
        BufferedImage bfImage = robot.createScreenCapture(new Rectangle(0, 0, width, height));
        String userDir = System.getProperty("user.dir");
        ImageIO.write(bfImage, "jpg", new File(userDir + fileName));
        Mat src = Imgcodecs.imread(userDir + fileName);
        Files.delete(Paths.get(userDir + fileName));
        return src;
    }

    /**
     * 大图找小图
     * @param targetImg
     */
    public static Point matchTemplate(String targetImg, double factor) {

        // 1.导入Opencv库
        OpenCV.loadShared();
        // 2.加载图像
        Mat src = getFullScreenShotByFile();
//        Mat src = Imgcodecs.imread(sourceImg);// 待匹配图片
        Mat template = Imgcodecs.imread(targetImg);// 获取匹配模板

        // 3.进行模板匹配
        // 创建一个输出图像
        Mat outputImage = new Mat(src.rows(), src.cols(), src.type());
        Imgproc.matchTemplate(src, template, outputImage, Imgproc.TM_CCOEFF_NORMED);

        // 4.获取匹配结果,查找最大匹配值
        Core.MinMaxLocResult result = Core.minMaxLoc(outputImage);
        org.opencv.core.Point matchLoc = result.maxLoc;
        double similarity = result.maxVal; //匹配度
        int x = (int) matchLoc.x; //小图大大图中的x坐标
        int y = (int) matchLoc.y; //小图大大图中的y坐标
        log.info("图片：{}，坐标：[{}，{}]，精确度：{}",targetImg, x, y, similarity);

//        //将查找到的结果标上框框
//        Imgproc.rectangle(src,new Point(x,y),new Point(x+template.cols(),y+template.rows()),
//                new Scalar( 0, 0, 255),2);
//        //5.显示结果
//        HighGui.imshow("模板匹配", src);
//        HighGui.waitKey();
        if(factor <= similarity){

            Size size = template.size();
            int width = (int)size.width;
            int height = (int)size.height;
            System.out.println("width:" + width + "," + height);
            return new Point(x + width/2, y + height/2);
        }else {
            return new Point();
        }
    }


}
